// #include <iostream>
// #include <iomanip>
#include <cmath>

#include "rvfft.hpp"
#include "instr_printer.hpp"

#define PRINT(instruction)  printer.add_instr(rvfft::instruction)


int main(int argc, char *argv[])
{
    InstrPrinter printer("/data/jsj/proj/nexus-am/apps/microbench/include/fft_test.h");

    // 2^L = FFT_Length
    // N为当前运算层数
    // N=1，2, … , L 从1开始
    // j表示该层数一共有几组蝶形运算
    // i表示该组蝶形运算需要运算多少次，因为vec限制，每次运算只能4+4个数
    // WnTable 第N层有2^(N-1)个数
    // ADDR(i)=ADDR+i*32bits(一个数32bits)
    const int L = (argc == 2)? std::stoul(argv[1], 0): 10;
    constexpr uint8_t v0 = 0;
    constexpr uint8_t v1 = 1;
    constexpr uint8_t v2 = 2;
    constexpr uint8_t v3 = 3;
    constexpr uint8_t v4 = 4;
    constexpr uint8_t v5 = 5;
    constexpr uint8_t v6 = 6;
    constexpr uint8_t v7 = 7;

    constexpr uint8_t t0 = 5;
    constexpr uint8_t t1 = 6;
    constexpr uint8_t t2 = 7;
    constexpr uint8_t t3 = 28;

    // base addr stored in register t0
    printer.add_line("void fft_4(){");
    printer.add_line("__asm__ volatile(");
    printer.add_line("\"li t0,0x00000000 \\n\\t\\");
    printer.add_line("nop \\n\\t\\");
    for (int layer=1; layer<=L; ++layer) {
        if (layer==1) {
            int len = (int)std::pow(2, L-2);
            for(int i=0; i<len; i++) {
                int offset = 4*i << 3;
     //4*i为当前运算到第几个数，<<3是因为一个数 32 bits，在16进制的地址上占8位
                
                printer.add_line("li", "t0", std::to_string(offset));
                printer.add_line("li", "t1", std::to_string(offset+16));
                
                PRINT(LDVEC<0>(t0, 0, v0));
                PRINT(LDVEC<1>(t1, 0, v0)); //64bits = 16*4 
                //PRINT(complex_mul<0>(i,1, v0));
                PRINT(butterfly_single<0>(v0));
                PRINT(SDVEC<0>(v0,  t0, 0));
                PRINT(SDVEC<1>(v0,  t1, 0));

                printf("layer is %d, i is %d\n",layer,i);
                printf("rvec0 is %d - %d\n",4*i,4*i+3);
            }
        }

        if (layer==2) {
            int len = (int)std::pow(2, L-2);
            for(int i=0; i<len; i++) {
                int offset = 4*i << 3;

                printer.add_line("li", "t0", std::to_string(offset));
                printer.add_line("li", "t1", std::to_string(offset+16));

                PRINT(LDVEC<0>(t0, 0,v0));
                PRINT(LDVEC<1>(t1, 0, v0));
                PRINT(complex_mul<1>(i,2, v0));
                PRINT(butterfly_single<1>(v0));
                PRINT(SDVEC<0>(v0,  t0, 0));
                PRINT(SDVEC<1>(v0,  t1, 0));
                printf("layer is %d, i is %d\n",layer,i);
                printf("rvec0 is %d - %d\n",4*i,4*i+3);


            }
        }

        if (layer>2) {
            int len_j = (int)std::pow(2, L-layer);
            int len_i = (int)std::pow(2, layer-3);
            for(int j=0; j<len_j; j++){
                for(int i=0; i<len_i; i++){
                //当前层数的数字序列为4*i+(2^layer)*j
                    int offset_v0 = (4*i+(int)std::pow(2, layer)*j) << 3;
                    int offset_v1 = (4*i+(int)std::pow(2, layer)*j+(int)std::pow(2, layer-1)) << 3;

                        printer.add_line("li", "t0", std::to_string(offset_v0));
                        printer.add_line("li", "t1", std::to_string(offset_v0+16));
                        printer.add_line("li", "t2", std::to_string(offset_v1));
                        printer.add_line("li", "t3", std::to_string(offset_v1+16));
                        
                        printf("layer is %d, i is %d, j is %d\n",layer,i,j);
                        printf("rvec0 is %d - %d\n",(4*i+(int)std::pow(2, layer)*j),(4*i+(int)std::pow(2, layer)*j) +3);
                        printf("rvec1 is %d - %d\n",(4*i+(int)std::pow(2, layer)*j+(int)std::pow(2, layer-1)),(4*i+(int)std::pow(2, layer)*j+(int)std::pow(2, layer-1))+3);

                        PRINT(LDVEC<0>(t0, 0, v0));
                        PRINT(LDVEC<1>(t1, 0, v0));
                        PRINT(LDVEC<0>(t2, 0, v1));
                        PRINT(LDVEC<1>(t3, 0, v1));
                        PRINT(complex_mul<2>(i,layer,v1));
                        PRINT(butterfly_double(v0, v1));
                        PRINT(write_buffer(v1));
                        PRINT(SDVEC<0>(v0, t0, 0));
                        PRINT(SDVEC<1>(v0, t1, 0));
                        PRINT(SDVEC<0>(v1, t2, 0));
                        PRINT(SDVEC<1>(v1, t3, 0));
                    
                }
            }
        }

    }
    printer.add_line("nop\"");
    printer.add_line(");");
    printer.add_line("}");
    return 0;
}
